﻿/* Copyright (C) 2012 by John Cronin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace davserv
{
    class Program
    {
        static void Main(string[] args)
        {
            if ((args.Length > 0) && (args[0] == "--passwd"))
                PasswdEditor();
            else
            {
                HttpServer serv = new HttpServer();
                serv.Start();
            }
        }

        static string auth_name = null;
        static string auth_init = null;
        static Auth.IAuthProvider auth = null;

        private static void PasswdEditor()
        {
            bool cont = true;
            while (cont)
            {
                DisplayPrompt();

                Console.Write("> ");
                string comm = Console.ReadLine();

                if (comm.StartsWith("auth "))
                {
                    string auth_method = comm.Substring("auth ".Length);
                    string test_auth_name = null;
                    string test_auth_init = null;

                    int first_bracket = auth_method.IndexOf('(');
                    if (first_bracket == -1)
                    {
                        test_auth_name = auth_method;
                        test_auth_init = "";
                    }
                    else
                    {
                        test_auth_init = auth_method.Substring(first_bracket).Trim('(', ')', ' ');
                        test_auth_name = auth_method.Substring(0, first_bracket);
                    }

                    try
                    {
                        Auth.IAuthProvider test_auth = Auth.GetAuthProvider(test_auth_name);
                        test_auth.Init(test_auth_init);
                        auth = test_auth;
                        auth_name = test_auth_name;
                        auth_init = test_auth_init;
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Invalid authorization method");
                    }
                }
                else if (comm.StartsWith("passwd "))
                {
                    if (auth == null)
                    {
                        Console.WriteLine("Please specify an authorization method first with the auth command");
                        continue;
                    }

                    string uname_realm = comm.Substring("passwd ".Length);
                    if (uname_realm == "")
                    {
                        Console.WriteLine("Syntax Error");
                        continue;
                    }

                    string[] arr = uname_realm.Split(' ');
                    if (arr.Length != 2)
                    {
                        Console.WriteLine("Syntax Error");
                        continue;
                    }

                    string username = arr[0];
                    string realm = arr[1];
                    string old_ha1 = auth.GetHA1Hash(username, realm);
                    string old_pass = "";

                    if (old_ha1 != null)
                    {
                        Console.Write("Old password: ");
                        old_pass = ReadPassword();
                    }
                    Console.Write("New password: ");
                    string new_pass = ReadPassword();
                    Console.Write("Confirm new password: ");
                    if (ReadPassword() != new_pass)
                    {
                        Console.WriteLine("Passwords do not match");
                        continue;
                    }

                    if (auth.SetPassword(username, realm, old_pass, new_pass) == true)
                        Console.WriteLine("Password changed successfully");
                    else
                        Console.WriteLine("Error changing password");
                }
                else if ((comm == "q") || (comm == "quit"))
                    cont = false;
            }
        }

        private static void DisplayPrompt()
        {
            if (auth == null)
                Console.WriteLine("auth: not selected");
            else
                Console.WriteLine("auth: " + auth_name + " (" + auth_init + ")");
        }

        private static string ReadPassword()
        {
            List<char> str = new List<char>();

            bool cont = true;
            while (cont)
            {
                ConsoleKeyInfo cki = System.Console.ReadKey(true);

                if (cki.Key == ConsoleKey.Backspace)
                {
                    if (str.Count > 0)
                        str.RemoveAt(str.Count - 1);
                }
                else if (cki.Key == ConsoleKey.Enter)
                {
                    Console.WriteLine();
                    cont = false;
                }
                else
                    str.Add(cki.KeyChar);
            }

            return new string(str.ToArray());
        }
    }
}
